

// TradeSpi.cpp: implementation of the CTradeSpi class.
//
//////////////////////////////////////////////////////////////////////

#include "TradeSpi.h"

#include <limits.h>
#include <sys/time.h>

#include <regex>

#include "BlowFish.h"
#include "msgs.h"
#include "mylogger.h"
#include "pthread.h"

#define LOG_MSG
double MIN_TIMER_INTERVAL_ = 0.855;  // in ms
vector<IPolicy *> *g_policy = nullptr;

IFutureAccount *CreateAccount(const char *pszConfigFile) {
  CTradeSpi *pSpi = new CTradeSpi(pszConfigFile);
  REM_EES_AccountInfo *pAcct = new REM_EES_AccountInfo();
  pAcct->m_pTradeSpi = pSpi;
  pSpi->m_pFutureAccount = pAcct;
  return pAcct;
}

/////////////////////////////////////////////////////////////////////
// CFClient Members;
/////////////////////////////////////////////////////////////////////
CFClient::CFClient(IPolicy *pPolicy, CTradeSpi *pTradeSpi, bool bIsSHFE,
                   char cHedgeType) {
  m_pPolicy = pPolicy;
  m_bIsSHFE = bIsSHFE;
  m_cHedgeType = cHedgeType;
  m_pTradeSpi = pTradeSpi;

  if (pTradeSpi != NULL) {
    if (!g_policy) {
      g_policy = pTradeSpi->Get_policy();
    }
    pTradeSpi->AddPolicy(pPolicy);
  }
  if (!exists_logger()) init_logger();
}

void CFClient::RegisterTimer(int nMillSecondsAfter, int nAction,
                             OrderField *pOrder) {
  if (m_pPolicy != NULL) {
    m_pTradeSpi->RegisterTimer((RemOrderField *)pOrder, nAction,
                               nMillSecondsAfter, m_pPolicy);
  }
}

void CFClient::Release() { delete this; }

void CFClient::LogError(const char *pszError) { m_pTradeSpi->Error(pszError); }

void CFClient::LogInfo(const char *pszError) { m_pTradeSpi->Info(pszError); }

void CFClient::LogDebug(const char *pszError) { m_pTradeSpi->Debug(pszError); }

void CFClient::SetSHFE(bool bSHFE) { m_bIsSHFE = bSHFE; }

OrderField *CFClient::Buy(const char *InstrumentID, int nVolume,
                          double fPrice) {
  return m_pTradeSpi->Buy(InstrumentID, nVolume, fPrice, m_pPolicy);
}

OrderField *CFClient::Sell(const char *InstrumentID, int nVolume, double fPrice,
                           int closeTd) {
  // return m_pTradeSpi->PlaceOrder(InstrumentID, USTP_FTDC_D_Sell,
  // USTP_FTDC_OF_CloseYesterday, nVolume, fPrice);
  printf("sell and  closetd is %d \n", closeTd);
  if (closeTd == 0) {
    return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_short,
                                   EES_SideType_close_long, nVolume, fPrice,
                                   m_pPolicy);
  } else if (closeTd == 1) {
    printf("sell and  closetd is 1 \n");
    return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_short,
                                   EES_SideType_close_today_long, nVolume,
                                   fPrice, m_pPolicy);
  } else if (closeTd == 2) {
    // closeTd == 2
    return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_short,
                                   EES_SideType_close_ovn_long, nVolume, fPrice,
                                   m_pPolicy);
  } else if (closeTd == 4) {
    // 自动平卖
    if (m_pTradeSpi->m_ees_pos.find(string(InstrumentID)) !=
        m_pTradeSpi->m_ees_pos.end()) {
      auto value = m_pTradeSpi->m_ees_pos[string(InstrumentID)];
      // int hold_pos = value.long_pre + value.long_today ;

      int today_frozen = 0, yd_frozen = 0;
      // 得到今仓frozen和昨仓frozen
      for (auto ele : value.frozen) {
        if (ele.second.side == EES_SideType_close_today_long) {
          today_frozen = today_frozen + ele.second.frozen_num;
        }
        if (ele.second.side == EES_SideType_close_ovn_long) {
          yd_frozen = today_frozen + ele.second.frozen_num;
        }
      }

      if (value.long_today - today_frozen < nVolume) {  // 需要平昨
        SPDLOG_INFO("long_pos_today {}  order vol{}", value.long_today,
                    nVolume);
        int today_closable = value.long_today - today_frozen;
        m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_short,
                                EES_SideType_close_today_long, today_closable,
                                fPrice, m_pPolicy);  // 平今
        return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_short,
                                       EES_SideType_close_ovn_long,
                                       nVolume - today_closable, fPrice,
                                       m_pPolicy);  // 平昨
      } else {
        SPDLOG_INFO("--long_pos_today {}  order vol{}", value.short_today,
                    nVolume);
        return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_short,
                                       EES_SideType_close_today_long, nVolume,
                                       fPrice, m_pPolicy);  // 平今
      }
    }
  }
}

OrderField *CFClient::Short(const char *InstrumentID, int nVolume,
                            double fPrice) {
  return m_pTradeSpi->Short(InstrumentID, nVolume, fPrice, m_pPolicy);
}

OrderField *CFClient::Cover(const char *InstrumentID, int nVolume,
                            double fPrice, int closeTd) {
  // return m_pTradeSpi->PlaceOrder(InstrumentID, USTP_FTDC_D_Buy,
  // USTP_FTDC_OF_CloseYesterday, nVolume, fPrice);
  if (closeTd == 0) {
    return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_long,
                                   EES_SideType_close_short, nVolume, fPrice,
                                   m_pPolicy);
  } else if (closeTd == 1) {
    return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_long,
                                   EES_SideType_close_today_short, nVolume,
                                   fPrice, m_pPolicy);
  } else if (closeTd == 2) {
    // closeTd == 2
    return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_long,
                                   EES_SideType_close_ovn_short, nVolume,
                                   fPrice, m_pPolicy);
  } else if (closeTd == 4) {
    if (m_pTradeSpi->m_ees_pos.find(string(InstrumentID)) !=
        m_pTradeSpi->m_ees_pos.end()) {
      auto value = m_pTradeSpi->m_ees_pos[string(InstrumentID)];
      // int hold_pos = value.long_pre + value.long_today ;

      int today_frozen = 0, yd_frozen = 0;
      // 得到今仓frozen和昨仓frozen
      for (auto ele : value.frozen) {
        if (ele.second.side == EES_SideType_close_today_short) {
          today_frozen = today_frozen + ele.second.frozen_num;
        }
        if (ele.second.side == EES_SideType_close_ovn_short) {
          yd_frozen = today_frozen + ele.second.frozen_num;
        }
      }

      if (value.short_today - today_frozen < nVolume) {  // 需要平昨
        SPDLOG_INFO("short_pos_today {}  order vol{}", value.short_today,
                    nVolume);
        int todayclose = value.short_today - today_frozen;
        m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_long,
                                EES_SideType_close_today_short, todayclose,
                                fPrice,
                                m_pPolicy);  // 平今
        return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_long,
                                       EES_SideType_close_ovn_short,
                                       nVolume - todayclose, fPrice,
                                       m_pPolicy);  // 平昨
      } else {                                      // 只平今
        SPDLOG_INFO("-- short_pos_today {}  order vol{}", value.short_today,
                    nVolume);

        return m_pTradeSpi->PlaceOrder(InstrumentID, EES_PosiDirection_long,
                                       EES_SideType_close_today_short, nVolume,
                                       fPrice, m_pPolicy);  // 平今
      }
    }
  }
}

//////////////////////////////////////////////////////////////////////
// CTradeSpi members;
//////////////////////////////////////////////////////////////////////

void *rem_hook(void *args) {
  // myinfo("start on timer thread.");
  TimerArgs *arg = (TimerArgs *)args;
  IPolicy *policy = arg->policy;
  int millisec = arg->millisec;
  OrderField *pOrder = arg->pOrder;
  // myinfo("start to delay " << millisec << " milliseconds.");
  // struct timeval time_begin, time_end;
  // gettimeofday(&time_begin, NULL);
  // myinfo("begin time : " << time_begin.tv_usec);
  usleep(millisec * 1000);
  // gettimeofday(&time_end, NULL);
  // myinfo("end time : " << time_end.tv_usec);
  //  TODO: use lData == 1
  policy->OnTimer(pOrder, 1);
}

CTradeSpi::CTradeSpi(const char *pszInitFile) : m_Config(pszInitFile) {
#ifdef LOG_MSG
  cout << "GetBroker   " << m_Config.GetBroker() << std::endl;
  cout << "GetUserId   " << m_Config.GetUser() << std::endl;
  cout << "GetInvestorID   " << m_Config.GetInvestorID() << std::endl;
  cout << "GetAppID    " << m_Config.GetAppID() << std::endl;
  cout << "GetAuthCode " << m_Config.GetAuthCode() << std::endl;
  cout << "GetFrontID  " << m_Config.GetFrontID() << std::endl;
  cout << "GetPassword " << m_Config.GetPassword() << std::endl;

  for (auto ele : m_Config.m_TradeServers) {
    cout << ele.first << "-----" << ele.second << std::endl;
    for (auto eles : *ele.second) {
      cout << eles << std::endl;
    }
  }

  for (auto ele : m_Config.m_TradeQueryServers) {
    cout << ele.first << "-----" << ele.second << std::endl;
    for (auto eles : *ele.second) {
      cout << eles << std::endl;
    }
  }

  for (auto ele : m_Config.m_TradeUdpServers) {
    cout << ele.first << "-----" << ele.second << std::endl;
    for (auto eles : *ele.second) {
      cout << eles << std::endl;
    }
  }
#endif
  // return ;
  SPDLOG_INFO("CTradeSpi Construct.");
  m_connected = false;
  b_authenticated = false;
  b_position = false;
  b_instruments = false;
  m_pTradeApi = CreateEESTraderApi();

  // std::string m_tradeServerIp = "183.129.220.106";
  // unsigned short  m_tradeServerPort = 60000;
  // std::string m_queryServerIp = "183.129.220.106";
  // unsigned short m_queryServerPort = 60001;

  auto trade_itr = (*m_Config.m_TradeServers["user1"]).begin();
  auto query_itr = (*m_Config.m_TradeQueryServers["user1"]).begin();

  string trade_ip = (*trade_itr).substr(0, (*trade_itr).find(":"));
  string trade_port = (*trade_itr).substr((*trade_itr).find(":") + 1);

  string query_ip = (*query_itr).substr(0, (*query_itr).find(":"));
  string query_port = (*query_itr).substr((*query_itr).find(":") + 1);

  // cout<< "GetAppID    " <<    trade_ip << std::endl;
  // cout<< "GetAuthCode " << trade_port << std::endl;
  // cout<< "GetFrontID  " <<  query_ip << std::endl;
  // cout<< "GetPassword " << query_port  << std::endl;

  EES_TradeSvrInfo svrInfo;

  // strcpy(svrInfo.m_remoteTradeIp, m_tradeServerIp.c_str());
  // svrInfo.m_remoteTradeTCPPort = m_tradeServerPort;
  // strcpy(svrInfo.m_remoteQueryIp, m_queryServerIp.c_str());
  // svrInfo.m_remoteQueryTCPPort = m_queryServerPort;

  strcpy(svrInfo.m_remoteTradeIp, trade_ip.c_str());
  svrInfo.m_remoteTradeTCPPort = stoi(trade_port);
  strcpy(svrInfo.m_remoteQueryIp, query_ip.c_str());
  svrInfo.m_remoteQueryTCPPort = stoi(query_port);

  if (m_Config.m_UsingUDP["user1"] == 1) {
    SPDLOG_INFO("using udp trade ");
    auto udp_itr = (*m_Config.m_TradeUdpServers["user1"]).begin();
    int udp_port = stoi((*udp_itr).substr((*udp_itr).find(":") + 1));

    svrInfo.m_remoteTradeUDPPort = udp_port;
    strcpy(svrInfo.m_LocalTradeIp, "9001");
    svrInfo.m_LocalTradeUDPPort = 9001;
  } else {
    svrInfo.m_remoteTradeUDPPort = 0;
    strcpy(svrInfo.m_LocalTradeIp, "");
    svrInfo.m_LocalTradeUDPPort = 0;
  }

  SPDLOG_INFO("trade connect ip {}", trade_ip);
  SPDLOG_INFO("trade connect port {}", trade_port);
  SPDLOG_INFO("trade query connect ip {}", query_ip);
  SPDLOG_INFO("trade query connect port {}", query_port);
  int ret_err = m_pTradeApi->ConnServer(svrInfo, this);

  int waitTime = 0;
  while (!m_connected) {
    sleep(1);
    waitTime++;
    if (waitTime >= 5) {
      printf("wait for connect response timeout!\n");
    }
  }

  // std::this_thread::sleep_for(std::chrono::seconds(10));
  // 	if (!exists_logger())
  // 		init_logger();
}

CTradeSpi::~CTradeSpi() {}

int CTradeSpi::GetLastErrorID() { return m_nLastError; }

char *CTradeSpi::GetLastErrorMsg() { return m_cLastError; }

void CTradeSpi::Log(const char *pszLog, int nLevel, long ThreadID) {}

void CTradeSpi::CloseLog() {
  if (m_pfLog != NULL) {
    fclose(m_pfLog);
    m_pfLog = NULL;
  }
}

void CTradeSpi::Debug(const char *pszLog) { PostLogMessage(pszLog, 0); }

void CTradeSpi::Info(const char *pszLog) { PostLogMessage(pszLog, 1); }

void CTradeSpi::Error(const char *pszLog) { PostLogMessage(pszLog, 2); }

void CTradeSpi::PostLogMessage(const char *pszLog, int nLevel) {}

IFutureTrader *CTradeSpi::CreateTrader(IPolicy *pPolicy, char cHedgeFlag,
                                       bool IsSHFE) {
  CFClient *pClient = new CFClient(pPolicy, this, IsSHFE, cHedgeFlag);
  pClient->m_pFutureAcct = m_pFutureAccount;
  m_ClientsLock.Lock();
  m_Clients.push_back(pClient);
  m_ClientsLock.Unlock();
  return pClient;
}

bool CTradeSpi::IsSHFE(const char *pszCode) {}

void CTradeSpi::FrozenPosition(RemOrderField *pOrder, const char *pszCode,
                               char cBuySell, char cClose, int nVolume) {}

void CTradeSpi::UnfrozenPosition(RemOrderField *pField) {}

int CTradeSpi::Login(const char *UserID, const char *Password, char *ErrorMsg,
                     int *ErrorID) {
  int nErrorID = Login(UserID, Password);
  if (nErrorID != 0) {
    strcpy(ErrorMsg, m_cLastError);
    *ErrorID = m_nLastError;
  } else {
    *ErrorID = 0;
    ErrorMsg[0] = '\0';
  }
  return nErrorID;
}

int CTradeSpi::Login(const char *pszUserID, const char *pszPassword) {
  // wait for login
  SPDLOG_INFO("wait for connected.");
  while (!m_connected) {
    sleep(1);
    SPDLOG_INFO("sleep for connected.");
  }

  // to do
  // SPDLOG_INFO("wait for b_instruments.");
  // while (!b_instruments)
  // {
  //     sleep(1);
  //     SPDLOG_INFO("sleep for b_instruments.");
  // }

  // SPDLOG_INFO("wait for b_position.");
  // while (!b_position)
  // {
  //     sleep(1);
  //     SPDLOG_INFO("sleep for b_position.");
  // }

  std::string m_logonId = m_Config.GetBroker();
  std::string m_logonPwd = m_Config.GetPassword();

  int rlt = m_pTradeApi->UserLogon(m_logonId.c_str(), m_logonPwd.c_str(),
                                   m_Config.GetAppID(), m_Config.GetAuthCode());
  SPDLOG_INFO(
      "login id is----> {} pwd is--->{} appid is---> {} AuthCode is---> {} "
      ".",
      m_logonId.c_str(), m_logonPwd.c_str(), m_Config.GetAppID(),
      m_Config.GetAuthCode());

  sleep(2);
  printf("QueryAccountOrder  acct is %s \n", acct_id.c_str());
  m_pTradeApi->QueryAccountOrder(acct_id.c_str());

  m_pTradeApi->QueryAccountBP(acct_id.c_str(), m_Config.GetNextRequestID());

  return rlt;
}
int CTradeSpi::ReqUserLogin() {
  // wait for login
  SPDLOG_INFO(" rem begin login ----.");

  std::string m_logonId = m_Config.GetBroker();
  std::string m_acct = m_Config.GetInvestorID();
  std::string m_logonPwd = m_Config.GetPassword();

  cout << "m_logonId --- " << m_logonId << std::endl;
  cout << "m_logonPwd--- " << m_logonPwd << std::endl;

  m_Config.SetInvestorID(m_acct.c_str());
  // int rlt =  m_pTradeApi->UserLogon(m_logonId.c_str(),
  // m_logonPwd.c_str(), "client", "client_auth_code");
  int rlt = 0;
  return rlt;
};
bool CTradeSpi::req_position() {
  //    test_order();
  long_pos_map_.clear();
  short_pos_map_.clear();

  EES_ClientToken order_token = 0;
  m_pTradeApi->GetMaxToken(&order_token);
  // std::cout << m_Config.GetInvestorID() << std::endl;
  int nTried = 0;
  int rlt = 1;
  //  m_pTradeApi->QueryAccountPosition(m_Config.GetInvestorID(), order_token);
  // SPDLOG_INFO("req_position.  InvestorID is  {}  tocken is {}",
  //            m_Config.GetInvestorID(), order_token);
  while (rlt != 0 && nTried++ < 3) {
    sleep(1);
    rlt = m_pTradeApi->QueryAccountPosition(m_Config.GetInvestorID(),
                                            order_token);
    SPDLOG_INFO("req_position. nRet : {}", rlt);
  }
  return rlt == 0;
}
void CTradeSpi::ReqUserInvestor() {  // m_pTradeApi->QueryUserAccount();
}

bool CTradeSpi::req_qry_instrument() {
  SPDLOG_INFO("req_qry_instrument.");
  future_instruments_.clear();

  int nTried = 0;
  int nRet = m_pTradeApi->QuerySymbolList();
  while (nRet != 0 && nTried++ < 3) {
    sleep(1);
    nRet = m_pTradeApi->QuerySymbolList();
    SPDLOG_INFO("req_qry_instrument. nRet : {}", nRet);
  }

  return nTried == 0;

  return 0;
}

int CTradeSpi::QueryAccount() {
  SPDLOG_INFO(
      "QueryAccount. m_Config.GetBroker(): {}, m_Config.GetInvestorID(): "
      "{}",
      m_Config.GetBroker(), m_Config.GetInvestorID());

  return 0;
}

int CTradeSpi::CheckMyOrderID(const char *psz) {}

void CTradeSpi::CacheTrade(EES_OrderExecutionField *pField) {}

void CTradeSpi::FlushCachedTrade(RemOrderField *pOrder) {}

void CTradeSpi::UpdatePosition(EES_OrderExecutionField *pField) {}

const char *CTradeSpi::GetInitFile() { return m_cInitFile; }

void CTradeSpi::CreateEmptyOrders() {}

RemOrderField *CTradeSpi::GetOrderByBrokerOID(const char *pszBrokerOrderID) {
  return NULL;
}

RemOrderField *CTradeSpi::GetNewOrder() { return NULL; }

RemOrderField *CTradeSpi::GetNewOrderNoLock() { return NULL; }

RemOrderField *CTradeSpi::GetNewOrderByID(int nOrderID) { return NULL; }

void CTradeSpi::GetLongPos(const char *pszIns, int &nTotal, int &nClosable,
                           int &nTodayClosable) {
  /*
  auto &pos_map = long_pos_map_;
  auto iter = pos_map.find(std::string(pszIns));
  if (iter != pos_map.end()) {
    nTotal = iter->second.m_TodayQty;
    nClosable = iter->second.m_TodayQty;
    nTodayClosable = iter->second.m_TodayQty - iter->second.m_InitOvnQty;
  }
  */
  SPDLOG_INFO("CTradeSpi::GetLongPos");

  auto iter = m_ees_pos.find(std::string(pszIns));
  if (iter != m_ees_pos.end()) {
    // getlong 的pos 对应frozen的 type应该是 EES_SideType_close_today_long or
    // EES_SideType_close_ovn_long
    auto frozen_map = iter->second.frozen;
    iter->second.print();
    int frozen_num = 0;
    for (auto ele : frozen_map) {
      if (ele.second.side == EES_SideType_close_today_long or
          ele.second.side == EES_SideType_close_ovn_long) {
        frozen_num = frozen_num + ele.second.frozen_num;
      }
    }

    nTotal = iter->second.long_pre + iter->second.long_today;
    nClosable = iter->second.long_pre + iter->second.long_today - frozen_num;
    nTodayClosable = iter->second.long_today;
  } else {
    SPDLOG_INFO("exception cant find {}  pos ", pszIns);
  }
}

void CTradeSpi::GetLongPos(const char *pszIns, int &nTotal, int &nClosable,
                           int &nTodayClosable, double &fAvgOpenPrice) {
  /*
  auto &pos_map = long_pos_map_;
  auto iter = pos_map.find(std::string(pszIns));
  if (iter != pos_map.end()) {
    nTotal = iter->second.m_TodayQty;
    nClosable = iter->second.m_TodayQty;
    nTodayClosable = iter->second.m_TodayQty - iter->second.m_InitOvnQty;
  }
  */

  auto iter = m_ees_pos.find(std::string(pszIns));
  if (iter != m_ees_pos.end()) {
    nTotal = iter->second.long_pre + iter->second.long_today;
    nClosable = iter->second.long_pre + iter->second.long_today;
    nTodayClosable = iter->second.long_today;
  }
}

void CTradeSpi::GetShortPos(const char *pszIns, int &nTotal, int &nClosable,
                            int &nTodayClosable) {
  SPDLOG_INFO("CTradeSpi::GetShortPos");
  /*
auto &pos_map = short_pos_map_;
auto iter = pos_map.find(std::string(pszIns));
if (iter != pos_map.end()) {
nTotal = iter->second.m_TodayQty;
nClosable = iter->second.m_TodayQty;
nTodayClosable = iter->second.m_TodayQty - iter->second.m_InitOvnQty;
}
*/

  auto iter = m_ees_pos.find(std::string(pszIns));
  if (iter != m_ees_pos.end()) {
    // getShort 的pos 对应frozen的 type应该是 EES_SideType_close_today_short
    // or EES_SideType_close_ovn_short
    iter->second.print();
    auto frozen_map = iter->second.frozen;
    int frozen_num = 0;
    for (auto ele : frozen_map) {
      if (ele.second.side == EES_SideType_close_today_short or
          ele.second.side == EES_SideType_close_ovn_short) {
        frozen_num = frozen_num + ele.second.frozen_num;
      }
    }

    nTotal = iter->second.short_pre + iter->second.short_today;
    nClosable = iter->second.short_pre + iter->second.short_today - frozen_num;
    nTodayClosable = iter->second.short_today;
  } else {
    SPDLOG_INFO("exception cant find {}  pos ", pszIns);
  }
}

void CTradeSpi::GetShortPos(const char *pszIns, int &nTotal, int &nClosable,
                            int &nTodayClosable, double &fAvgOpenPrice) {
  /*
  auto &pos_map = short_pos_map_;
  auto iter = pos_map.find(std::string(pszIns));
  if (iter != pos_map.end()) {
    nTotal = iter->second.m_TodayQty;
    nClosable = iter->second.m_TodayQty;
    nTodayClosable = iter->second.m_TodayQty - iter->second.m_InitOvnQty;
  }
  */
  auto iter = m_ees_pos.find(std::string(pszIns));
  if (iter != m_ees_pos.end()) {
    nTotal = iter->second.short_pre + iter->second.short_today;
    nClosable = iter->second.short_pre + iter->second.short_today;
    nTodayClosable = iter->second.short_today;
  }
}

struct InstrumentField *CTradeSpi::GetInstrument(const char *pszInstrument) {
  SPDLOG_INFO("CTradeSpi::GetInstrument");
  if (m_symbol_info.find(string(pszInstrument)) != m_symbol_info.end()) {
    return &m_symbol_info[string(pszInstrument)];
  } else {
    return nullptr;
  }
}

void CTradeSpi::GetInstrument(const char *pszProductID,
                              FutureInstrumentField **ppIns, int *pCount) {
  SPDLOG_INFO("CTradeSpi::GetInstrument **ppIns ");
}

bool CTradeSpi::GetInstrument(FutureInstrumentField *pIns) {
  string inst = string(pIns->InstrumentID);
  if (m_symbol_info.find(inst) != m_symbol_info.end()) {
    strcpy(pIns->ExchangeID, m_symbol_info[inst].CtpIns.ExchangeID);
    strcpy(pIns->ExpireDate, m_symbol_info[inst].CtpIns.ExpireDate);
    strcpy(pIns->InstrumentID, m_symbol_info[inst].CtpIns.InstrumentID);
    pIns->MarginRate = m_symbol_info[inst].CtpIns.LongMarginRatio;
    pIns->PriceTick = m_symbol_info[inst].CtpIns.PriceTick;
    string product_cls;
    product_cls.push_back(m_symbol_info[inst].CtpIns.ProductClass);
    strcpy(pIns->ProductClass, product_cls.c_str());
    pIns->VolumeMultiply = m_symbol_info[inst].CtpIns.VolumeMultiple;
    return true;
  } else {
    return false;
  }
}

int CTradeSpi::GetMultiply(const char *pszInstrument) {}

struct CThostFtdcRspInstrumentField *CTradeSpi::GetCtpInstrument(
    const char *pszInstrument) {}

TradeField *CTradeSpi::GetNextTradeField() {}

void CTradeSpi::SetBgTaskState(bool bInBg) { m_bInBg = bInBg; }

void CTradeSpi::OnOneSecond() {}

void CTradeSpi::RegisterTimer(RemOrderField *pOrder, int nAction,
                              int nMilliSecondsAfter, IPolicy *pListener) {
  // TODO: nAction == 1
  pthread_t pid;
  TimerArgs *args = new TimerArgs;
  args->millisec = nMilliSecondsAfter;
  args->policy = pListener;
  args->pOrder = pOrder;
  if (pthread_create(&pid, NULL, rem_hook, args) != 0)
    SPDLOG_ERROR("Register Timer Error.");

  pthread_detach(pid);
}

void CTradeSpi::GetLongAvgPrice(const char *pszIns, double &fAvgOpenPrice,
                                double &fAvgPositionPrice) {}

void CTradeSpi::GetShortAvgPrice(const char *pszIns, double &fAvgOpenPrice,
                                 double &fAvgPositionPrice) {}

void CTradeSpi::OnFutureMarketData(MarketDataField *pData) {}

bool CTradeSpi::IsFinished(RemOrderField *pOrder) {}

/////////////////////////////////////////////////////////////////////
// REM_EES_AccountInfo Members;
/////////////////////////////////////////////////////////////////////
int REM_EES_AccountInfo::Login(const char *UserID, const char *Password,
                               char *ErrorMsg, int *ErrorID) {
  SPDLOG_INFO("Account Login");
  SPDLOG_INFO("Account Login  UserID is{}  Password is{}", UserID, Password);
  strcpy(m_cUser, "39660821");
  strcpy(m_cPassword, "1");
  // strcpy(m_cUser,UserID);
  // strcpy(m_cPassword,Password);
  return m_pTradeSpi->Login(m_cUser, m_cPassword, ErrorMsg, ErrorID);
}

const char *REM_EES_AccountInfo::GetUser() { return m_cUser; }

const char *REM_EES_AccountInfo::GetPassword() { return m_cPassword; }

int REM_EES_AccountInfo::Logout() { return m_pTradeSpi->Logout(); }

IFutureTrader *REM_EES_AccountInfo::CreateTrader(IPolicy *pPolicy,
                                                 char cHedgeFlag, bool IsSHFE) {
  return m_pTradeSpi->CreateTrader(pPolicy, cHedgeFlag, IsSHFE);
}

void REM_EES_AccountInfo::Stop() { m_pTradeSpi->Stop(); }

void REM_EES_AccountInfo::Release() {
  m_pTradeSpi->Release();
  delete this;
}

// rem spi

void CTradeSpi::OnConnection(ERR_NO errNo, const char *pErrStr) {
  m_connected = true;
  SPDLOG_INFO("rem OnConnection");
  std::cout << "[em OnConnection]" << std::endl;
  this->ReqUserLogin();
  ;
}
/// 连接断开消息的回调

/// \brief	服务器主动断开，会收到这个消息
/// \param  ERR_NO errNo         连接成功能与否的消息
/// \param  const char* pErrStr  错误信息
/// \return void

void CTradeSpi::OnDisConnection(ERR_NO errNo, const char *pErrStr) {
  SPDLOG_INFO("rem  DisConnection");
}
/// 登录消息的回调

/// \param  pLogon                  登录成功或是失败的结构
/// \return void

void CTradeSpi::OnUserLogon(EES_LogonResponse *pLogon) {
  if (pLogon->m_Result != NO_ERROR) {
    SPDLOG_INFO("UserLogin Res Fail {}! ", pLogon->m_Result);
  } else {
    SPDLOG_INFO(
        "UserLogin Res Success !.  TradingDay : {}, MaxLocalID : "
        "{},UserId:{}",
        pLogon->m_TradingDate, pLogon->m_MaxToken, pLogon->m_UserId);
  }
  long maxOrder = pLogon->m_MaxToken;
  // myinfo("Start Local ID : " << maxOrder);
  if (maxOrder < 90000) maxOrder = 90001;
  SPDLOG_INFO("Start Local ID : {}", maxOrder);
  m_Config.SetMaxOrderRef(maxOrder);
  m_Config.SetTradingDay(std::to_string(pLogon->m_TradingDate).c_str());
  m_pTradeApi->QueryUserAccount();
  req_position();
  req_qry_instrument();

  // this->ReqUserInvestor();
}
/// 修改密码响应回调
/// \param  nResult                  服务器响应的成功与否返回码
/// \return void
void CTradeSpi::OnRspChangePassword(EES_ChangePasswordResult nResult) {}
/// 查询用户下面帐户的返回事件

/// \param  pAccountInfo	        帐户的信息
/// \param  bFinish	                如果没有传输完成，这个值是 false
/// ，如果完成了，那个这个值为 true \remark 如果碰到 bFinish ==
/// true，那么是传输结束，并且 pAccountInfo值无效。 \return void

void CTradeSpi::OnQueryUserAccount(EES_AccountInfo *pAccoutnInfo,
                                   bool bFinish) {
  if (pAccoutnInfo != nullptr) {
    SPDLOG_INFO("Query m_Account OK.  m_Account : {}", pAccoutnInfo->m_Account);
    m_Account = *pAccoutnInfo;
    if (string(pAccoutnInfo->m_Account).size() > 0) {
      acct_id = string(pAccoutnInfo->m_Account);
      printf("acct_id %s \n", acct_id.c_str());
    }
    // if (pAccoutnInfo->m_Account[0] != '\0' )
    //     m_Config.SetInvestorID(pAccoutnInfo->m_Account);

  }

  else {
    SPDLOG_ERROR("Query InvestorID Error. ErrorID ");
  }
}

/// 查询帐户下面期货仓位信息的返回事件
/// \param  pAccount	                帐户ID
/// \param  pAccoutnPosition	        帐户的仓位信息
/// \param  nReqId		                发送请求消息时候的ID号。
/// \param  bFinish
/// 如果没有传输完成，这个值是false，如果完成了，那个这个值为 true \remark
/// 如果碰到 bFinish == true，那么是传输结束，并且 pAccountInfo值无效。
/// \return void
void CTradeSpi::OnQueryAccountPosition(const char *pAccount,
                                       EES_AccountPosition *pInvestorPosition,
                                       int nReqId, bool bFinish) {
  SPDLOG_INFO("OnRspQryInvestorPosition ");
  if (pInvestorPosition == nullptr) {
    SPDLOG_ERROR("OnRspQryInvestorPosition  ErrorID");
  } else {
    if (pInvestorPosition != nullptr &&
        string(pInvestorPosition->m_Symbol).size() > 0) {
      EES_AccountPosition pos = {0};
      memcpy(&pos, pInvestorPosition, sizeof(EES_AccountPosition));
      SPDLOG_INFO("-----------------------------------");
      SPDLOG_INFO("OnRspQryInvestorPosition  InstrumentID= {}",
                  pInvestorPosition->m_Symbol);
      SPDLOG_INFO("OnRspQryInvestorPosition  Position= {}",
                  pInvestorPosition->m_TodayQty);
      SPDLOG_INFO("OnRspQryInvestorPosition  YdPosition= {}",
                  pInvestorPosition->m_InitOvnQty);

      auto &pos_map = pos.m_PosiDirection == 1 ? long_pos_map_
                                               : short_pos_map_;  /// 多头是 1
      auto iter = pos_map.find(std::string(pos.m_Symbol));
      if (iter != pos_map.end()) {
        pos.m_TodayQty = pos.m_TodayQty + iter->second.m_TodayQty;
        pos.m_TodayQty = pos.m_InitOvnQty + iter->second.m_InitOvnQty;
      }
      pos_map[std::string(pInvestorPosition->m_Symbol)] = pos;

      if (m_ees_pos.find(std::string(pInvestorPosition->m_Symbol)) !=
          m_ees_pos.end()) {
        // do nothibg
      } else {
        m_ees_pos[string(pInvestorPosition->m_Symbol)] = RemPostion();
      }

      RemPostion &rem_pos = m_ees_pos[string(pInvestorPosition->m_Symbol)];
      if (pos.m_PosiDirection == 1) {  // 多
        rem_pos.long_pre = rem_pos.long_pre + pos.m_InitOvnQty;
        rem_pos.long_today = rem_pos.long_today + pos.m_TodayQty;

        // SPDLOG_INFO("this long_today {}", rem_pos.long_today);
        printf("------------long_today >  %d \n", rem_pos.long_today);

      } else {  // 空
        rem_pos.short_pre = rem_pos.short_pre + pos.m_InitOvnQty;
        rem_pos.short_today = rem_pos.short_today + pos.m_TodayQty;
        printf("------------short_today >  %d \n", rem_pos.short_today);

        // SPDLOG_INFO("----->short_today {}", rem_pos.short_today);
      }
      rem_pos.print();
    }

    if (bFinish) {
      SPDLOG_INFO("OnRspQryInvestorPosition  done.");
      b_position = true;
    }
  }
}
/// 查询帐户下面期权仓位信息的返回事件, 注意这个回调,
/// 和上一个OnQueryAccountPosition, 会在一次QueryAccountPosition请求后,
/// 分别返回, 先返回期货, 再返回期权, 即使没有期权仓位,
/// 也会返回一条bFinish=true的记录 \param  pAccount	                帐户ID
/// \param  pAccoutnPosition	        帐户的仓位信息
/// \param  nReqId		                发送请求消息时候的ID号。
/// \param  bFinish
/// 如果没有传输完成，这个值是false，如果完成了，那个这个值为 true \remark
/// 如果碰到 bFinish == true，那么是传输结束，并且 pAccountInfo值无效。
/// \return void
void CTradeSpi::OnQueryAccountOptionPosition(
    const char *pAccount, EES_AccountOptionPosition *pAccoutnOptionPosition,
    int nReqId, bool bFinish) {}
/// 查询帐户下面资金信息的返回事件

/// \param  pAccount	                帐户ID
/// \param  pAccoutnPosition	        帐户的仓位信息
/// \param  nReqId		                发送请求消息时候的ID号
/// \return void

void CTradeSpi::OnQueryAccountBP(const char *pAccount,
                                 EES_AccountBP *pAccoutnPosition, int nReqId) {
  if (pAccoutnPosition == nullptr) {
    SPDLOG_ERROR("OnQueryAccountBP  ErrorID");
  } else {
    m_account_bp = *pAccoutnPosition;
  }
}
/// 查询合约列表的返回事件

/// \param  pSymbol	                    合约信息
/// \param  bFinish	                    如果没有传输完成，这个值是
/// false，如果完成了，那个这个值为 true \remark 如果碰到 bFinish ==
/// true，那么是传输结束，并且 pSymbol 值无效。 \return void

void CTradeSpi::OnQuerySymbol(EES_SymbolField *pRspInfo, bool bFinish) {
  if (pRspInfo == nullptr) {
    SPDLOG_ERROR("OnRspQryInstrument  ErrorID");
  } else {
    EES_SymbolField field = {0};
    memcpy(&field, pRspInfo, sizeof(EES_SymbolField));
    future_instruments_[field.m_symbol] = field;

    //            SPDLOG_INFO("OnRspQryInstrument. InstrumentID:  {},
    //            future_instruments_.size = {}", field.m_symbol ,
    //            future_instruments_.size());

    InstrumentField info;
    strcpy(info.CtpIns.InstrumentID, pRspInfo->m_symbol);
    switch (pRspInfo->m_ExchangeID) {
      case 100: {
        strcpy(info.CtpIns.ExchangeID, "SSE");
        break;
      }
      case 101: {
        strcpy(info.CtpIns.ExchangeID, "SZSE");
        break;
      }
      case 102: {
        strcpy(info.CtpIns.ExchangeID, "CFFEX");
        break;
      }
      case 103: {
        strcpy(info.CtpIns.ExchangeID, "SHFE");
        break;
      }
      case 104: {
        strcpy(info.CtpIns.ExchangeID, "DCE");
        break;
      }
      case 105: {
        strcpy(info.CtpIns.ExchangeID, "CZCE");
        break;
      }
      case 106: {
        strcpy(info.CtpIns.ExchangeID, "INE");
        break;
      }
      case 107: {
        strcpy(info.CtpIns.ExchangeID, "SGE");
        break;
      }
    }

    strcpy(info.CtpIns.InstrumentName, pRspInfo->m_symbolName);
    strcpy(info.CtpIns.ProductID, pRspInfo->m_ProdID);
    info.CtpIns.DeliveryYear = pRspInfo->m_DeliveryYear;
    info.CtpIns.DeliveryMonth = pRspInfo->m_DeliveryMonth;

    info.CtpIns.MaxMarketOrderVolume = pRspInfo->m_MaxMarketOrderVolume;
    info.CtpIns.MinMarketOrderVolume = pRspInfo->m_MinMarketOrderVolume;
    info.CtpIns.MaxLimitOrderVolume = pRspInfo->m_MaxLimitOrderVolume;
    info.CtpIns.MinLimitOrderVolume = pRspInfo->m_MinLimitOrderVolume;

    info.CtpIns.VolumeMultiple = pRspInfo->m_VolumeMultiple;
    info.CtpIns.PriceTick = pRspInfo->m_PriceTick;

    strcpy(info.CtpIns.CreateDate, to_string(pRspInfo->m_CreateDate).c_str());
    strcpy(info.CtpIns.OpenDate, to_string(pRspInfo->m_OpenDate).c_str());
    strcpy(info.CtpIns.ExpireDate, to_string(pRspInfo->m_ExpireDate).c_str());
    strcpy(info.CtpIns.StartDelivDate,
           to_string(pRspInfo->m_StartDelivDate).c_str());
    strcpy(info.CtpIns.EndDelivDate,
           to_string(pRspInfo->m_EndDelivDate).c_str());

    switch (pRspInfo->m_InstLifePhase) {
      case 0: {
        info.CtpIns.InstLifePhase = THOST_FTDC_IP_NotStart;
        break;
      }
      case 1: {
        info.CtpIns.InstLifePhase = THOST_FTDC_IP_Started;
        break;
      }
      case 2: {
        info.CtpIns.InstLifePhase = THOST_FTDC_IP_Pause;
        break;
      }
      case 3: {
        info.CtpIns.InstLifePhase = THOST_FTDC_IP_Expired;
        break;
      }
    }

    info.CtpIns.IsTrading = pRspInfo->m_InstLifePhase;
    info.CtpIns.StrikePrice = pRspInfo->m_StrikePrice;
    if (pRspInfo->m_CallPut == 'C') {  // C:认购
      info.CtpIns.OptionsType = '1';
    } else if (pRspInfo->m_CallPut == 'P') {
      info.CtpIns.OptionsType = '2';
    }
    // info.CtpIns.OptionsType = pRspInfo->m_CallPut;

    strcpy(info.CtpIns.UnderlyingInstrID, pRspInfo->m_UnderlyingSymbol);

    m_symbol_info[string(pRspInfo->m_symbol)] = info;
    if (bFinish) {
      b_instruments = true;
    }
  }
}
/// 查询帐户交易保证金的返回事件

/// \param  pAccount                    帐户ID
/// \param  pSymbolMargin               帐户的保证金信息
/// \param  bFinish	                    如果没有传输完成，这个值是
/// false，如果完成，那个这个值为 true \remark 如果碰到 bFinish ==
/// true，那么是传输结束，并且 pSymbolMargin 值无效。 \return void

void CTradeSpi::OnQueryAccountTradeMargin(const char *pAccount,
                                          EES_AccountMargin *pSymbolMargin,
                                          bool bFinish) {}
/// 查询帐户交易费用的返回事件

/// \param  pAccount                    帐户ID
/// \param  pSymbolFee	                帐户的费率信息
/// \param  bFinish	                    如果没有传输完成，这个值是
/// false，如果完成了，那个这个值为 true \remark 如果碰到 bFinish == true
/// ，那么是传输结束，并且 pSymbolFee 值无效。 \return void

void CTradeSpi::OnQueryAccountTradeFee(const char *pAccount,
                                       EES_AccountFee *pSymbolFee,
                                       bool bFinish) {}
/// 下单被柜台系统接受的事件

/// \brief 表示这个订单已经被柜台系统正式的接受
/// \param  pAccept	                    订单被接受以后的消息体
/// \return void

void CTradeSpi::OnOrderAccept(EES_OrderAcceptField *pOrder) {
  SPDLOG_INFO(
      "OnRtnOrder called. m_MarketOrderToken = {}  client_token = {}, "
      "Status = "
      "{}",
      pOrder->m_MarketOrderToken, pOrder->m_ClientOrderToken,
      pOrder->m_OrderState);

  string orderId(std::to_string(pOrder->m_ClientOrderToken));
  IPolicy *policy = NULL;
  RemOrderField *field = NULL;

  m_OrderLock.Lock();
  map<string, IPolicy *>::iterator pIter = policies.find(orderId);
  if (pIter != policies.end()) {
    // myinfo("OrderID found in policies.");
    policy = pIter->second;
    map<string, RemOrderField *>::iterator ctpIter =
        RemOrderFields.find(orderId);
    if (ctpIter != RemOrderFields.end()) {
      field = ctpIter->second;
      // myinfo("OrderID found in OrderFields.");
    } else {
      SPDLOG_INFO("OrderID is not found in OrderFields. OrderID : {}", orderId);
    }
  } else {
    SPDLOG_ERROR("OrderID is not found in Policies. OrderID : {}", orderId);
  }
  m_OrderLock.Unlock();

  if (policy == NULL) {
    SPDLOG_ERROR("policy is NULL");
    return;
  }
  if (field == NULL) {
    SPDLOG_ERROR("field is NULL");
  }

  if (policy != NULL && field != NULL) {
    field->OrderID = pOrder->m_MarketOrderToken;
    strcpy(field->InstrumentID, pOrder->m_Symbol);
    if (pOrder->m_Side == EES_SideType_open_long ||
        pOrder->m_Side == EES_SideType_close_today_short ||
        pOrder->m_Side == EES_SideType_close_ovn_short ||
        pOrder->m_Side == EES_SideType_close_short) {
      field->OpenClose = '0';

    } else {
      field->OpenClose = '1';
    }

    // field->OpenClose = pOrder->m_Side;
    field->Direction = pOrder->m_Side;
    // to do
    // strcpy(field->ExchangeID, pOrder->m_Exchange);
    strcpy(field->OrderSysID,
           std::to_string(pOrder->m_MarketOrderToken).c_str());
    // field->OrderStatus = pOrder->m_OrderState;
    //  to do
    //  strcpy(field->InsertTime, pOrder->InsertTime);

    // strcpy(field->TradingDay, pOrder->TradingDay);

    if (pOrder->m_OrderState == EES_OrderState_order_accept ||
        pOrder->m_OrderState == EES_OrderState_order_triggered) {
      field->OrderStatus = '3';
    } else if (pOrder->m_OrderState == EES_OrderState_order_active) {
      field->OrderStatus = 'a';
    }

    field->Price = pOrder->m_Price;
    field->Volume = pOrder->m_Qty;
    field->HedgeFlag = pOrder->m_HedgeFlag;

    char status = field->OrderStatus;
    int lastTraded = field->TradedVolume;
    int thisTimeTraded = 0;
    int left = 0;
    SPDLOG_INFO("filed   Status = {} Rem Status{} openclose {}",
                field->OrderStatus, pOrder->m_OrderState, field->OpenClose);
    policy->OnFOrderChanged(field, thisTimeTraded, left, status);

    // 2023 add pos update 这里只更新forzen
    {
      if (m_ees_pos.find(string(field->InstrumentID)) != m_ees_pos.end()) {
        auto &pos = m_ees_pos[string(field->InstrumentID)];
        FroznPos frozen;
        frozen.side = m_orderid_side[pOrder->m_ClientOrderToken].side;
        frozen.frozen_num = frozen.frozen_num + pOrder->m_Qty;
        pos.frozen[pOrder->m_ClientOrderToken] = frozen;
        pos.print();
      } else {
        RemPostion pos;
        FroznPos frozen;
        frozen.side = m_orderid_side[pOrder->m_ClientOrderToken].side;
        frozen.frozen_num = frozen.frozen_num + pOrder->m_Qty;
        pos.frozen[pOrder->m_ClientOrderToken] = frozen;
        m_ees_pos[string(field->InstrumentID)] = pos;
        pos.print();
      }
    }
    // this call  just for strategy test
    // field->OrderStatus = 'a';
    // policy->OnFOrderChanged(field, thisTimeTraded, left, 'a');

    return;
  }
}
/// 下单被市场接受的事件
/// \brief 表示这个订单已经被交易所正式的接受
/// \param  pAccept 订单被接受以后的消息体，里面包含了市场订单ID \return
/// void
void CTradeSpi::OnOrderMarketAccept(EES_OrderMarketAcceptField *pOrder) {
  // 由于缺乏  EES_OrderMarketAcceptField ticker信息 故不在这里写

  SPDLOG_INFO("OnOrderMarketAccept . OrderID = {} , exchange Status = {}",
              pOrder->m_MarketOrderToken, pOrder->m_ExchangeStatus);
  return;
}

///	下单被柜台系统拒绝的事件
/// \brief	订单被柜台系统拒绝，可以查看语法检查或是风控检查。

/// \param  pReject	                    订单被接受以后的消息体
/// \return void

void CTradeSpi::OnOrderReject(EES_OrderRejectField *pReject) {
  printf("---------------------------------------------------------\n");
  printf("OnOrderReject\n");
  printf("---------------------------------------------------------\n");
  printf("ClientOrderToken:     %d\n", pReject->m_ClientOrderToken);
  printf("ReasonCode      :     %d\n", int(pReject->m_ReasonCode));
  printf("GrammerText     :     %s\n", pReject->m_GrammerText);
  printf("RiskText        :     %s\n", pReject->m_RiskText);
  printf("\n");
}
///	下单被市场拒绝的事件
/// \brief	订单被市场拒绝，可以查看语法检查或是风控检查。
/// \param  pReject 订单被接受以后的消息体，里面包含了市场订单ID \return
/// void
void CTradeSpi::OnOrderMarketReject(EES_OrderMarketRejectField *pReject) {
  printf("---------------------------------------------------------\n");
  printf("OnOrderMarketReject\n");
  printf("---------------------------------------------------------\n");
  printf("Exchange OrderSysID  :     %lld\n", pReject->m_MarketOrderToken);
  printf("Reason Text          :     %.100s\n", pReject->m_ReasonText);
  printf("\n");
}
// 撤单拒接
void CTradeSpi::OnCxlOrderReject(EES_CxlOrderRej *pReject) {
  printf("---------------------------------------------------------\n");
  printf("OnCxlOrderReject\n");
  printf("---------------------------------------------------------\n");
  printf("Exchange m_MarketOrderToken  :     %lld\n",
         pReject->m_MarketOrderToken);
  printf("Reason Text          :     %.100s\n", pReject->m_ReasonText);
  printf("\n");
}

///	订单成交的消息事件

/// \brief	成交里面包括了订单市场ID，建议用这个ID查询对应的订单
/// \param  pExec 订单被接受以后的消息体，里面包含了市场订单ID \return void

void CTradeSpi::OnOrderExecution(EES_OrderExecutionField *pTrade) {
  SPDLOG_INFO("OnOrderExecution. OrderID = {}, TradeID = {}",
              pTrade->m_MarketOrderToken, pTrade->m_MarketExecID);
  string orderId(std::to_string(pTrade->m_ClientOrderToken));

  IPolicy *policy = NULL;
  RemOrderField *pOrder = NULL;

  m_OrderLock.Lock();
  map<string, IPolicy *>::iterator pIter = policies.find(orderId);
  if (pIter != policies.end()) {
    policy = pIter->second;
    map<string, RemOrderField *>::iterator orderIter =
        RemOrderFields.find(orderId);
    if (orderIter != RemOrderFields.end()) {
      pOrder = orderIter->second;
    } else {
      SPDLOG_INFO("OrderID is not found in OrderFields. OrderID : {}", orderId);
    }
  } else {
    SPDLOG_ERROR("OrderID is not found in Policies. OrderID : {}", orderId);
  }
  m_OrderLock.Unlock();

  if (policy != NULL && pOrder != NULL) {
    TradeField *trade = new TradeField;
    memset(trade, 0, sizeof(TradeField));

    trade->OrderID = pTrade->m_MarketOrderToken;
    // to do
    // strcpy(trade->InstrumentID, pTrade->m);
    // strcpy(trade->ExchangeID, pTrade->ExchangeID);
    trade->Price = pTrade->m_Price;
    trade->Volume = pTrade->m_Quantity;

    /*
        if (pTrade == EES_OrderStatus_shengli_accept) {
          trade->CurrentOrderStatus = 'c';
        } else if (pOrder->OrderStatus == EES_OrderStatus_mkt_accept) {
          trade->CurrentOrderStatus = '3';
        } else if (pOrder->OrderStatus == EES_OrderStatus_executed) {
          trade->CurrentOrderStatus = '0';
        } else if (pOrder->OrderStatus == EES_OrderStatus_cancelled) {
          trade->CurrentOrderStatus = '5';
        }
    */
    // trade->CurrentOrderStatus = pOrder->OrderStatus;
    trade->CurrentOrderStatus = '0';
    trade->VolumeTotal = pTrade->m_Quantity;

    // strcpy(trade->OrderSysID, pTrade->m_MarketExecID);
    // strcpy(trade->TradeID, pTrade->TradeID);
    // strcpy(trade->TradeTime, pTrade->TradeTime);

    policy->OnFOrderChanged(pOrder, 0, 0, trade->CurrentOrderStatus);
    policy->OnFOrderFilled(pOrder, trade);
    string symbol;
    {
      // update postion
      if (m_orderid_side.find(pTrade->m_ClientOrderToken) !=
          m_orderid_side.end()) {
        EES_SideType curr_side =
            m_orderid_side[pTrade->m_ClientOrderToken].side;
        symbol = m_orderid_side[pTrade->m_ClientOrderToken].symbol;
        switch (curr_side) {
          case EES_SideType_open_long: {  // 开今 long     +今 pos
            m_ees_pos[symbol].long_today =
                m_ees_pos[symbol].long_today + pTrade->m_Quantity;
            break;
          }
          case EES_SideType_close_today_long: {  // 平今 long     - 今 pos
            m_ees_pos[symbol].long_today =
                m_ees_pos[symbol].long_today - pTrade->m_Quantity;
            break;
          }
          case EES_SideType_open_short: {  // 开今 short     +今 short_pos
            m_ees_pos[symbol].short_today =
                m_ees_pos[symbol].short_today + pTrade->m_Quantity;
            break;
          }
          case EES_SideType_close_today_short: {  // 平今 short     -今
                                                  // short_pos
            m_ees_pos[symbol].short_today =
                m_ees_pos[symbol].short_today - pTrade->m_Quantity;
            break;
          }
          case EES_SideType_close_ovn_long: {
            m_ees_pos[symbol].long_pre =
                m_ees_pos[symbol].long_pre - pTrade->m_Quantity;
            break;
          }
          case EES_SideType_close_ovn_short: {
            m_ees_pos[symbol].short_pre =
                m_ees_pos[symbol].short_pre - pTrade->m_Quantity;

            break;
          }
        }

      } else {
        SPDLOG_INFO("order  { } position  update exception",
                    pTrade->m_ClientOrderToken);
      }
    }

    // 更新frozen
    {
      auto &curr_pos = m_ees_pos[symbol];
      if (curr_pos.frozen.find(pTrade->m_ClientOrderToken) !=
          curr_pos.frozen.end()) {
        auto &frozen_info = curr_pos.frozen[pTrade->m_ClientOrderToken];
        frozen_info.frozen_num = frozen_info.frozen_num - pTrade->m_Quantity;
        if (frozen_info.frozen_num < 0) {
          frozen_info.frozen_num = 0;
          SPDLOG_INFO(
              "trade update frozen exception  frozen_num < 0   order_id {}",
              pTrade->m_ClientOrderToken);
        }

      } else {
        SPDLOG_INFO(
            "trade update frozen exception can't find m_ClientOrderToken   "
            "order_id {}",
            pTrade->m_ClientOrderToken);
      }
    }
    return;
  }
}
///	订单成功撤销事件

/// \brief	成交里面包括了订单市场ID，建议用这个ID查询对应的订单
/// \param  pCxled 订单被接受以后的消息体，里面包含了市场订单ID \return void

void CTradeSpi::OnOrderCxled(EES_OrderCxled *pCxled) {
  SPDLOG_INFO("OnOrderCxled  called    cancel success  client id {}",
              pCxled->m_ClientOrderToken);

  string orderId(std::to_string(pCxled->m_ClientOrderToken));
  IPolicy *policy = NULL;
  RemOrderField *field = NULL;

  m_OrderLock.Lock();
  map<string, IPolicy *>::iterator pIter = policies.find(orderId);
  if (pIter != policies.end()) {
    // myinfo("OrderID found in policies.");
    policy = pIter->second;
    map<string, RemOrderField *>::iterator ctpIter =
        RemOrderFields.find(orderId);
    if (ctpIter != RemOrderFields.end()) {
      field = ctpIter->second;
      // myinfo("OrderID found in OrderFields.");
    } else {
      SPDLOG_INFO("OrderID is not found in OrderFields. OrderID : {}", orderId);
    }
  } else {
    SPDLOG_ERROR("OrderID is not found in Policies. OrderID : {}", orderId);
  }
  m_OrderLock.Unlock();

  if (policy == NULL) {
    SPDLOG_ERROR("policy is NULL");
    return;
  }
  if (field == NULL) {
    SPDLOG_ERROR("field is NULL");
  }
  // 更新frozen cancel情况下只要找到对应orderid的frozen,减去该值就可以了
  {
    auto ticker = m_orderid_side[pCxled->m_ClientOrderToken].symbol;
    auto &curr_pos = m_ees_pos[ticker];
    if (curr_pos.frozen.find(pCxled->m_ClientOrderToken) !=
        curr_pos.frozen.end()) {
      auto &frozen_info = curr_pos.frozen[pCxled->m_ClientOrderToken];
      frozen_info.frozen_num = frozen_info.frozen_num - pCxled->m_Decrement;
      if (frozen_info.frozen_num < 0) {
        frozen_info.frozen_num = 0;
        SPDLOG_INFO(
            "cancel update frozen exception  frozen_num < 0   order_id {}",
            pCxled->m_ClientOrderToken);
      }

    } else {
      SPDLOG_INFO(
          "cancel update frozen exception can't find m_ClientOrderToken   "
          "order_id {}",
          pCxled->m_ClientOrderToken);
    }

    // 更新撤单信息
    if (m_inst_cancel_num.find(ticker) != m_inst_cancel_num.end()) {
      m_inst_cancel_num[ticker] = m_inst_cancel_num[ticker] + 1;
    } else {
      m_inst_cancel_num[ticker] = 1;
    }
  }

  if (policy != NULL && field != NULL) {
    field->OrderID = pCxled->m_MarketOrderToken;

    field->OrderStatus = '5';
    SPDLOG_INFO("filed   Status = {}", field->OrderStatus);
    policy->OnFOrderChanged(field, 0, 0, field->OrderStatus);
  }
}

///	撤单被拒绝的消息事件

/// \brief	一般会在发送撤单以后，收到这个消息，表示撤单被拒绝
/// \param  pReject	                   撤单被拒绝消息体
/// \return void

/// \brief	查询订单信息时候的回调，这里面也可能包含不是当前用户下的订单
/// \param  pAccount                 帐户ID
/// \param  pQueryOrder	             查询订单的结构
/// \param  bFinish	                 如果没有传输完成，这个值是
/// false，如果完成了，那个这个值为 true \remark 如果碰到 bFinish ==
/// true，那么是传输结束，并且 pQueryOrder值无效。 \return void

void CTradeSpi::OnQueryTradeOrder(const char *pAccount,
                                  EES_QueryAccountOrder *pQueryOrder,
                                  bool bFinish) {
  printf(" OnQueryTradeOrder  m_ClientOrderToken %d  m_orderStatus %d \n",
         pQueryOrder->m_ClientOrderToken, pQueryOrder->m_OrderStatus);
  string ticker = string(pQueryOrder->m_symbol);
  if (pQueryOrder->m_OrderStatus == EES_OrderStatus_cancelled) {
    if (m_inst_cancel_num.find(ticker) != m_inst_cancel_num.end()) {
      m_inst_cancel_num[ticker] = m_inst_cancel_num[ticker] + 1;
    } else {
      m_inst_cancel_num[ticker] = 1;
    }
  }
  if (pQueryOrder->m_OrderStatus == EES_OrderStatus_mkt_accept ||
      pQueryOrder->m_OrderStatus == EES_OrderStatus_shengli_accept) {
    if (m_ees_pos.find(ticker) != m_ees_pos.end()) {
      // do nothing
    } else {
      RemPostion rem_pos;
      m_ees_pos[ticker] = rem_pos;
    }
    auto &frozen_map = m_ees_pos[ticker].frozen;
    FroznPos pos;
    pos.frozen_num = pQueryOrder->m_Quantity;
    pos.side = pQueryOrder->m_SideType;
    frozen_map[pQueryOrder->m_ClientOrderToken] = pos;
  }
}

int CTradeSpi::GetCancelingNum(const char *inst) {
  if (m_inst_cancel_num.find(string(inst)) != m_inst_cancel_num.end()) {
    return m_inst_cancel_num[string(inst)];
  } else {
    return 0;
  }
}
///	查询订单的返回事件

/// \brief	查询订单信息时候的回调，这里面也可能包含不是当前用户下的订单成交
/// \param  pAccount                        帐户ID
/// \param  pQueryOrderExec	                查询订单成交的结构
/// \param  bFinish
/// 如果没有传输完成，这个值是false，如果完成了，那个这个值为 true \remark
/// 如果碰到 bFinish == true，那么是传输结束，并且pQueryOrderExec值无效。
/// \return void

void CTradeSpi::OnQueryTradeOrderExec(const char *pAccount,
                                      EES_QueryOrderExecution *pQueryOrderExec,
                                      bool bFinish) {
  printf(" OnQueryTradeOrderExec  m_ClientOrderToken %d  \n",
         pQueryOrderExec->m_ClientOrderToken);
}
///	接收外部订单的消息

/// \brief	一般会在系统订单出错，进行人工调整的时候用到。
/// \param  pPostOrder	                    查询订单成交的结构
/// \return void

void CTradeSpi::OnPostOrder(EES_PostOrder *pPostOrder) {}
///	接收外部订单成交的消息

/// \brief	一般会在系统订单出错，进行人工调整的时候用到。
/// \param  pPostOrderExecution	             查询订单成交的结构
/// \return void

void CTradeSpi::OnPostOrderExecution(
    EES_PostOrderExecution *pPostOrderExecution) {}
///	查询交易所可用连接的响应
/// \brief	每个当前系统支持的汇报一次，当bFinish=
/// true时，表示所有交易所的响应都已到达，但本条消息本身不包含有用的信息。
/// \param  pPostOrderExecution	             查询订单成交的结构
/// \return void
void CTradeSpi::OnQueryMarketSession(EES_ExchangeMarketSession *pMarketSession,
                                     bool bFinish) {}
///	交易所连接状态变化报告，
/// \brief	当交易所连接发生连接/断开时报告此状态
/// \param  MarketSessionId: 交易所连接代码
/// \param  ConnectionGood:
/// true表示交易所连接正常，false表示交易所连接断开了。 \return void
void CTradeSpi::OnMarketSessionStatReport(EES_MarketSessionId MarketSessionId,
                                          bool ConnectionGood) {}
///	合约状态变化报告
/// \brief	当合约状态发生变化时报告
/// \param  pSymbolStatus: 参见EES_SymbolStatus合约状态结构体定义
/// \return void
void CTradeSpi::OnSymbolStatusReport(EES_SymbolStatus *pSymbolStatus) {}
///	合约状态查询响应
/// \brief  响应合约状态查询请求
/// \param  pSymbolStatus: 参见EES_SymbolStatus合约状态结构体定义
/// \param	bFinish:
/// 当为true时，表示查询所有结果返回。此时pSymbolStatus为空指针NULL \return
/// void
void CTradeSpi::OnQuerySymbolStatus(EES_SymbolStatus *pSymbolStatus,
                                    bool bFinish) {}

void CTradeSpi::test_order() {
  // printf("test order \n");
  EES_ClientToken order_token = 0;
  m_pTradeApi->GetMaxToken(&order_token);

  EES_EnterOrderField temp;
  memset(&temp, 0, sizeof(EES_EnterOrderField));
  temp.m_Tif = EES_OrderTif_Day;
  temp.m_HedgeFlag = EES_HedgeFlag_Speculation;

  strcpy(temp.m_Account, "3966082");
  strcpy(temp.m_Symbol, "zn2307");
  temp.m_Side = EES_SideType_open_long;
  // temp.m_Side = EES_SideType_open_short;
  temp.m_Exchange = EES_ExchangeID_shfe;
  temp.m_SecType = EES_SecType_fut;
  temp.m_Price = 2100.0;
  temp.m_Qty = 20;
  temp.m_ClientOrderToken = order_token + 1;

  int ret = m_pTradeApi->EnterOrder(&temp);
  if (ret != NO_ERROR) {
    printf("send order failed(%d)\n", ret);
    return;
  }

  //(const char *pszCode,int nVolume,double fPrice,IPolicy
  //*pOrderListener=NULL,char HedgeFlag=EES_HedgeFlag_Speculation,char
  // cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int
  // nMinVolume=0){
  // this->Sell("zn2307",20,2200,nullptr,);
}
